/*=============================================================================
  D3DShaders.cpp : Direct3D specific effectors/shaders functions implementation.
  Copyright 2001 Crytek Studios. All Rights Reserved.

  Revision history:
    * Created by Honich Andrey

=============================================================================*/

#include "StdAfx.h"
#include "DriverD3D.h"
#include <I3DEngine.h>

//==================================================================================

bool CShader::FXSetTechnique(const CCryNameTSCRC& Name)
{
  assert (gRenDev->m_pRT->IsRenderThread());

  uint32 i;
  SShaderTechnique *pTech = NULL;
  for (i=0; i<m_HWTechniques.Num(); i++)
  {
    pTech = m_HWTechniques[i];
    if (pTech && Name == pTech->m_NameCRC)
      break;
  }
  if (i == m_HWTechniques.Num())
    return false;

  CRenderer *rd = gRenDev;
  rd->m_RP.m_pShader = this;
  rd->m_RP.m_nShaderTechnique = i;
  rd->m_RP.m_pCurTechnique = m_HWTechniques[i];

  return true;
}

bool CShader::FXSetPSFloat(const CCryNameR& NameParam, const Vec4* fParams, int nParams)
{
  CRenderer *rd = gRenDev;
  if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique)
    return false;
  SShaderPass *pPass = rd->m_RP.m_pCurPass;
  if (!pPass)
    return false;
  CHWShader_D3D *curPS = (CHWShader_D3D *)pPass->m_PShader;
  if (!curPS)
    return false;
  SCGBind *pBind = curPS->mfGetParameterBind(NameParam);
  if (!pBind)
    return false;
#if defined (DIRECT3D9)
  curPS->mfParameterf(pBind, &fParams[0].x, eHWSC_Pixel);
#elif defined (DIRECT3D10)
  curPS->mfParameterReg(pBind->m_dwBind, pBind->m_dwCBufSlot, eHWSC_Pixel, &fParams[0].x, nParams, curPS->m_pCurInst->m_nMaxVecs[pBind->m_dwCBufSlot]);
#endif
  return true;
}

bool CShader::FXSetVSFloat(const CCryNameR& NameParam, const Vec4* fParams, int nParams)
{
  CRenderer *rd = gRenDev;
  if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique)
    return false;
  SShaderPass *pPass = rd->m_RP.m_pCurPass;
  if (!pPass)
    return false;
  CHWShader_D3D *curVS = (CHWShader_D3D *)pPass->m_VShader;
  if (!curVS)
    return false;
  SCGBind *pBind = curVS->mfGetParameterBind(NameParam);
  if (!pBind)
    return false;
#if defined (DIRECT3D9)
  curVS->mfParameterf(pBind, &fParams[0].x, eHWSC_Vertex);
#elif defined (DIRECT3D10)
  curVS->mfParameterReg(pBind->m_dwBind, pBind->m_dwCBufSlot, eHWSC_Vertex, &fParams[0].x, nParams, curVS->m_pCurInst->m_nMaxVecs[pBind->m_dwCBufSlot]);
#endif
  return true;
}

bool CShader::FXBegin(uint32 *uiPassCount, uint32 nFlags)
{
  CRenderer *rd = gRenDev;
  if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique || !rd->m_RP.m_pCurTechnique->m_Passes.Num())
    return false;
  *uiPassCount = rd->m_RP.m_pCurTechnique->m_Passes.Num();
  rd->m_RP.m_nFlagsShaderBegin = nFlags;
  rd->m_RP.m_pCurPass = &rd->m_RP.m_pCurTechnique->m_Passes[0];
  return true;
}

bool CShader::FXBeginPass(uint32 uiPass)
{
	FUNCTION_PROFILER_RENDER_FLAT
  CD3D9Renderer *rd = gcpRendD3D;
  if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique || uiPass >= rd->m_RP.m_pCurTechnique->m_Passes.Num())
    return false;
  rd->m_RP.m_pCurPass = &rd->m_RP.m_pCurTechnique->m_Passes[uiPass];
  SShaderPass *pPass = rd->m_RP.m_pCurPass;
  //assert (pPass->m_VShader && pPass->m_PShader);
  //if (!pPass->m_VShader || !pPass->m_PShader)
  //  return false;
  CHWShader_D3D *curVS = (CHWShader_D3D *)pPass->m_VShader;
  CHWShader_D3D *curPS = (CHWShader_D3D *)pPass->m_PShader;
#if defined (DIRECT3D10) && !defined(PS3) && !defined(CAFE)
  CHWShader_D3D *curGS = (CHWShader_D3D *)pPass->m_GShader;
  CHWShader_D3D *curCS = (CHWShader_D3D *)pPass->m_CShader;
#endif

  bool bResult = true;

  // Set Pixel-shader and all associated textures
  if (curPS)
  {
  if (rd->m_RP.m_nFlagsShaderBegin & FEF_DONTSETTEXTURES)
    bResult &= curPS->mfSet(0);
  else
    bResult &= curPS->mfSet(HWSF_SETTEXTURES);
    curPS->mfSetParametersPI(NULL, NULL);
  }
  // Set Vertex-shader
  if (curVS)
  {
  curVS->mfSet(0);
    curVS->mfSetParametersPI(NULL, rd->m_RP.m_pShader);
  }

#if defined (DIRECT3D10) && !defined(PS3) && !defined(CAFE)
  // Set Geometry-shader
  if (curGS)
    bResult &= curGS->mfSet(0);
  else
    CHWShader_D3D::mfBindGS(NULL, NULL);

  // Set Compute-shader
  if (curCS)
    bResult &= curCS->mfSet(0);
  else
    CHWShader_D3D::mfBindCS(NULL, NULL);
#endif

  if (!(rd->m_RP.m_nFlagsShaderBegin & FEF_DONTSETSTATES))
  {
    rd->FX_SetState(pPass->m_RenderState);
    if (pPass->m_eCull != -1)
      rd->D3DSetCull((ECull)pPass->m_eCull);
  }

  return bResult;
}

bool CShader::FXEndPass()
{
  CRenderer *rd = gRenDev;
  if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique || !rd->m_RP.m_pCurTechnique->m_Passes.Num())
    return false;
  rd->m_RP.m_pCurPass = NULL;
  return true;
}

bool CShader::FXEnd()
{
  CRenderer *rd = gRenDev;
  if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique)
    return false;
  return true;
}

bool CShader::FXCommit(const uint32 nFlags)
{
  gcpRendD3D->FX_Commit();

  return true;
}


#if defined(DIRECT3D10) && !defined(PS3) && !defined(CAFE)
void *CHWShader_D3D::GetVSDataForDecl(const D3D11_INPUT_ELEMENT_DESC *pDecl, int nCount, int& nDataSize)
{
  nDataSize = 0;
  CShader *pSh = CShaderMan::m_ShaderFPEmu;
  if (!pSh || !pSh->m_HWTechniques.Num() || !nCount)
    return NULL;
  uint32 i, j;

  SShaderTechnique *pTech = NULL;
  for (i=0; i<pSh->m_HWTechniques.Num(); i++)
  {
    if (!stricmp(pSh->m_HWTechniques[i]->m_NameStr.c_str(), "InputLayout"))
    {
      pTech = pSh->m_HWTechniques[i];
      break;
    }
  }
  if (!pTech || !pTech->m_Passes.Num())
    return NULL;
  SShaderPass& Pass = pTech->m_Passes[0];
  CHWShader_D3D *pVS = (CHWShader_D3D *)Pass.m_VShader;
  if (!pVS)
    return NULL;

  uint32 nMask = 0;
//m_RP.m_FlagsShader_LT = m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorOp[0] | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaOp[0] << 8) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorArg[0] << 16) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaArg[0] << 24);

  for (i=0; i<nCount; i++)
  {
    const D3D11_INPUT_ELEMENT_DESC& Desc = pDecl[i];
    if (Desc.InputSlot != 0)
    {
      nMask |= 1<<Desc.InputSlot;
      if (nMask & VSM_TANGENTS)
      {
        for (j=0; j<nCount; j++)
        {
          const D3D11_INPUT_ELEMENT_DESC& Desc = pDecl[j];
          if (!strcmp(Desc.SemanticName, "BINORMAL"))
          {
            nMask |= (1<<VSF_QTANGENTS);
            break;
          }
        }
      }
    }
    else
    if (!strcmp(Desc.SemanticName, "POSITION"))
    {
      if (Desc.Format == DXGI_FORMAT_R32G32_FLOAT)
        nMask |= 0<<8;
      else
      if (Desc.Format == DXGI_FORMAT_R32G32B32_FLOAT)
        nMask |= 1<<8;
      else
      if (Desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT || Desc.Format == DXGI_FORMAT_R32G32B32A32_FLOAT)
        nMask |= 2<<8;
      else
        assert(0);
    }
    else
    if (!strcmp(Desc.SemanticName, "TEXCOORD"))
    {
      int nShift = 0;
      if (Desc.SemanticIndex == 0)
      {
        nMask |= eCA_Texture<<16;
        nShift = 10;
        if (Desc.Format == DXGI_FORMAT_R32G32_FLOAT || Desc.Format == DXGI_FORMAT_R16G16_FLOAT)
          nMask |= 0 << nShift;
        else
        if (Desc.Format == DXGI_FORMAT_R32G32B32_FLOAT)
          nMask |= 1 << nShift;
        else
        if (Desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT || Desc.Format == DXGI_FORMAT_R32G32B32A32_FLOAT)
          nMask |= 2 << nShift;
        else
          assert(0);
      }
      else
      if (Desc.SemanticIndex == 1)
      {
				if (nMask & (eCA_Constant<<19))
				{
					// PSIZE and TEX1 used together
					nMask &= ~(0x7<<19);
					nMask |= eCA_Previous<<19;
				}
				else
					nMask |= eCA_Texture1<<19;
      }
      else
        assert(0);
    }
    else
    if (!strcmp(Desc.SemanticName, "COLOR"))
    {
      int nShift = 0;
      if (Desc.SemanticIndex == 0)
      {
        nMask |= eCA_Diffuse<<24;
        nShift = 12;
        if (Desc.Format == DXGI_FORMAT_R32G32B32_FLOAT)
          nMask |= 1<<nShift;
        else
        if (Desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || Desc.Format == DXGI_FORMAT_R32G32B32A32_FLOAT)
          nMask |= 2<<nShift;
        else
          assert(0);
      }
      else
      if (Desc.SemanticIndex == 1)
      {
        nMask |= eCA_Specular<<27;
      }
      else
      {
        assert(0);
      }
    }
    else
    if (!strcmp(Desc.SemanticName, "NORMAL"))
    {
      if (Desc.SemanticIndex == 0)
        nMask |= eCA_Normal<<27;
      else
      {
        assert(0);
      }
      //assert (Desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM);
    }
    else
    if (!strcmp(Desc.SemanticName, "PSIZE"))
    {
      if (Desc.SemanticIndex == 0)
			{
				if (nMask & (eCA_Texture1<<19))
				{
					// PSIZE and TEX1 used together
					nMask &= ~(0x7<<19);
					nMask |= eCA_Previous<<19;
				}
				else
					nMask |= eCA_Constant<<19;
			}
      else
      {
        assert(0);
      }
      assert (Desc.Format == DXGI_FORMAT_R32G32B32A32_FLOAT);
    }
    else
    {
      assert(0);
    }
  }

  SShaderCombIdent Ident;
  Ident.m_LightMask = nMask;
  Ident.m_RTMask = 0;
  Ident.m_MDMask = 0;
  Ident.m_MDVMask = 0;
  Ident.m_GLMask = 0;

  SHWSInstance *pI = pVS->m_pCurInst;

  uint32 nFlags = HWSF_STOREDATA;
  SHWSInstance *pInst = pVS->mfGetInstance(pSh, Ident, nFlags); 
  if (!pVS->mfCheckActivation(pSh, pInst, nFlags))
  {
    pVS->m_pCurInst = pI;
    return NULL;
  }
  pVS->m_pCurInst = pI;

  nDataSize = pInst->m_nDataSize;
  return pInst->m_pShaderData;
}
#endif

//===================================================================================

void CRenderer::RefreshSystemShaders()
{
  // make sure all system shaders are properly refreshed during loading!
  gRenDev->m_cEF.mfRefreshSystemShader("AmbientOcclusion",	CShaderMan::m_ShaderAmbientOcclusion);
  gRenDev->m_cEF.mfRefreshSystemShader("Common",	CShaderMan::m_ShaderCommon);
  gRenDev->m_cEF.mfRefreshSystemShader("Debug",	CShaderMan::m_ShaderDebug);
  gRenDev->m_cEF.mfRefreshSystemShader("DeferredCaustics",	CShaderMan::m_ShaderDeferredCaustics);
  gRenDev->m_cEF.mfRefreshSystemShader("DeferredRain",	CShaderMan::m_ShaderDeferredRain);
  gRenDev->m_cEF.mfRefreshSystemShader("DeferredSnow",	CShaderMan::m_ShaderDeferredSnow);
  gRenDev->m_cEF.mfRefreshSystemShader("DeferredShading",	CShaderMan::m_shDeferredShading);
  gRenDev->m_cEF.mfRefreshSystemShader("DepthOfField",	CShaderMan::m_shPostDepthOfField);
  gRenDev->m_cEF.mfRefreshSystemShader("DXTCompress",	CShaderMan::m_ShaderDXTCompress);
  gRenDev->m_cEF.mfRefreshSystemShader("FarTreeSprites",	CShaderMan::m_ShaderTreeSprites);
  gRenDev->m_cEF.mfRefreshSystemShader("LightFlares",	CShaderMan::m_ShaderLightFlares);
  gRenDev->m_cEF.mfRefreshSystemShader("MotionBlur",	CShaderMan::m_shPostMotionBlur);
  gRenDev->m_cEF.mfRefreshSystemShader("OcclusionTest",	CShaderMan::m_ShaderOcclTest);
  gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame",	CShaderMan::m_shPostEffectsGame);
  gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsRenderModes",	CShaderMan::m_shPostEffectsRenderModes);
  gRenDev->m_cEF.mfRefreshSystemShader("ScreenSpaceGI",	CShaderMan::m_ShaderScreenSpaceGI);
  gRenDev->m_cEF.mfRefreshSystemShader("ShadowBlur",	CShaderMan::m_ShaderShadowBlur);
  gRenDev->m_cEF.mfRefreshSystemShader("Stereo",	CShaderMan::m_ShaderStereo);
  gRenDev->m_cEF.mfRefreshSystemShader("Sunshafts",	CShaderMan::m_shPostSunShafts);
	gRenDev->m_cEF.mfRefreshSystemShader("LightPropagationVolumes",	CShaderMan::m_ShaderLPV);
}

bool CD3D9Renderer::FX_SetFPMode()
{
  assert (gRenDev->m_pRT->IsRenderThread());

  if (!(m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & (RBPF_FP_DIRTY | RBPF_FP_MATRIXDIRTY)) && CShaderMan::m_ShaderFPEmu == m_RP.m_pShader)
    return true;
  if (m_bDeviceLost)
    return false;
  m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_FP_DIRTY | RBPF_FP_MATRIXDIRTY;
  m_RP.m_ObjFlags &= ~FOB_TRANS_MASK;
  m_RP.m_pCurObject = m_RP.m_TempObjects[m_RP.m_nProcessThreadID][0];
  CShader *pSh = CShaderMan::m_ShaderFPEmu;
  if (!pSh || !pSh->m_HWTechniques.Num())
    return false;
  m_RP.m_FlagsShader_LT = m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorOp | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaOp<<8) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorArg<<16) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaArg<<24);
  if (CTexture::s_TexStages[0].m_Texture && CTexture::s_TexStages[0].m_Texture->GetTextureType() == eTT_Cube)
    m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_CUBEMAP0];
  else
    m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_CUBEMAP0];

  m_RP.m_pShader = pSh;
  m_RP.m_pCurTechnique = pSh->m_HWTechniques[0];

  bool bRes = pSh->FXBegin(&m_RP.m_nNumRendPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
  if (!bRes)
    return false;
  bRes = pSh->FXBeginPass(0);
  FX_Commit();
  return bRes;
}


void CShaderMan::mfCheckObjectDependParams(std::vector<SCGParam>& PNoObj, std::vector<SCGParam>& PObj, EHWShaderClass eSH, CShader *pFXShader)
{
  if (!PNoObj.size())
    return;
  uint32 i;
  for (i=0; i<PNoObj.size(); i++)
  {
    SCGParam *prNoObj = &PNoObj[i];
    if ((prNoObj->m_eCGParamType & 0xff) == ECGP_PM_Tweakable)
    {
      int nType = prNoObj->m_eCGParamType & 0xff;
      prNoObj->m_eCGParamType = (ECGParam)nType;
    }

    if (prNoObj->m_Flags & PF_INSTANCE)
    {
#if defined (DIRECT3D10) || defined(PS3)
      if (prNoObj->m_dwCBufSlot != CB_STATIC_INSTANCE)
#endif
      {
        PObj.push_back(PNoObj[i]);
        PNoObj.erase(PNoObj.begin()+i);
        i--;
      }
#if defined (DIRECT3D10) || defined(PS3)
      else
      {
        assert (eSH == eHWSC_Vertex);
        //assert(j != pFXShader->m_InstParams.size());
        PNoObj.erase(PNoObj.begin()+i);
        i--;
      }
#endif
    }
    else
    if (prNoObj->m_Flags & PF_MATERIAL)
    {
#ifdef DIRECT3D10
      PNoObj.erase(PNoObj.begin()+i);
      i--;
#endif
    }
    else
    if (prNoObj->m_Flags & PF_LIGHT)
    {
      PNoObj.erase(PNoObj.begin()+i);
      i--;
    }
    else
    if (prNoObj->m_Flags & (PF_GLOBAL | PF_SHADOWGEN))
    {
      bool bCam = (prNoObj->m_eCGParamType == ECGP_Matr_PF_ViewProjMatrix || prNoObj->m_eCGParamType == ECGP_Matr_PF_ViewProjZeroMatrix || prNoObj->m_eCGParamType == ECGP_PF_NearFarDist);
      CHWShader_D3D::mfAddGlobalParameter(PNoObj[i], eSH, (prNoObj->m_Flags & PF_SHADOWGEN)!=0, bCam);
      PNoObj.erase(PNoObj.begin()+i);
      i--;
    }
  }
  if (PObj.size())
  {
    int n = -1;
    for (i=0; i<PObj.size(); i++)
    {
      if (PObj[i].m_eCGParamType == ECGP_Matr_PI_ViewProj)
      {
        n = i;
        break;
      }
    }
    if (n > 0)
    {
      SCGParam pr = PObj[n];
      PObj[n] = PObj[0];
      PObj[0] = pr;
    }
  }
}

static bool sIsSharedLevelCacheValid(const SResFileLookupData* pResData, CResFile *pRF)
{
  CShaderMan& man = gRenDev->m_cEF;
  if (!pResData || !pResData->m_SharedIdents.size())
    return false;
  uint32 i;
  for (i=0; i<pResData->m_SharedIdents.size(); i++)
  {
    const SSharedIdent &Ident = pResData->m_SharedIdents[i];
    FXShaderBinPathItor it = gRenDev->m_cEF.m_Bin.m_BinPaths.find(Ident.m_Name);
    if (it == gRenDev->m_cEF.m_Bin.m_BinPaths.end())
    {
      assert(0);
      return false;
    }
    const char *szBinPath = it->second.c_str();
    const SResFileLookupData* pResDataI = man.m_ResLookupDataMan[CACHE_READONLY].GetData(szBinPath);
    if (!pResDataI || pResData->m_CRC32 != pResDataI->m_CRC32)
      return false;
  }
  return true;
}

bool CShaderMan::mfPreactivate2(CResFileLookupDataMan& LevelLookup, 
																string szPathPerLevel, string szPathGlobal, 
																bool bVS, bool bPersistent)
{
  bool bRes = true;
  struct _finddata_t fileinfo;
  intptr_t handle;

  handle = gEnv->pCryPak->FindFirst (szPathPerLevel + "/*.*", &fileinfo);
  if (handle == -1)
    return bRes;

  do
  {
    if (fileinfo.name[0] == '.')
      continue;
    if (fileinfo.attrib & _A_SUBDIR)
    {
      bRes &= mfPreactivate2(LevelLookup, szPathPerLevel + "/" + fileinfo.name, 
				szPathGlobal + "/" + fileinfo.name, bVS, bPersistent);
      continue;
    }
    string StrPerLevel = szPathPerLevel + "/" + fileinfo.name;
    CResFile *pRes = new CResFile(StrPerLevel.c_str());
    int bR = pRes->mfOpen(RA_READ, &LevelLookup);
    if (!bR)
    {
      bRes = false;
      SAFE_DELETE(pRes);
      continue;
    }

		bool bCheckSharedCache = true;

		// name in the global cache used to retrieve the localup data
		string StrGlobal = szPathGlobal + "/" + fileinfo.name;

    SResFileLookupData *pLookupGlobal = gRenDev->m_cEF.m_ResLookupDataMan[CACHE_READONLY].GetData(StrGlobal.c_str());
    if (!pLookupGlobal)
    {
      SAFE_DELETE(pRes);
      continue;
    }
    SResFileLookupData *pLookupLevel = NULL;
    if (!bPersistent)
    {
      CCryNameTSCRC name = LevelLookup.AdjustName(pRes->mfGetFileName());
      pLookupLevel = LevelLookup.GetData(name);
    }
    else
    {
      // Startup cache
      const char *szName = pRes->mfGetFileName();
			CCryNameTSCRC name;
      if (strnicmp(szName, "ShaderCache/", 12) == 0) {
				stack_string sName = stack_string("Shaders/Cache/") + stack_string(&szName[12]);
				name = sName.c_str();
			} else if (strnicmp(szName, "Shaders/Cache/", 14) == 0) {
				name = LevelLookup.AdjustName(pRes->mfGetFileName());
				bCheckSharedCache = false; // don't need to check if shared cache is valid when precaching the global cache
			}	else {
        Warning("Wrong virtual directory in ShaderCacheStartup.pak");
        SAFE_DELETE(pRes);
        continue;
      }
      pLookupLevel = LevelLookup.GetData(name);
    }
    if (!pLookupLevel)
    {
      SAFE_DELETE(pRes);
      continue;
    }
    if (pLookupLevel->m_CacheMajorVer != pLookupGlobal->m_CacheMajorVer || pLookupLevel->m_CacheMinorVer != pLookupGlobal->m_CacheMinorVer || pLookupLevel->m_CRC32 != pLookupGlobal->m_CRC32)
    {
      SAFE_DELETE(pRes);
      continue;
    }
    const char *s = StrPerLevel.c_str();
    const uint32 nLen = strlen(s);
    int nStart = -1;
    int nEnd = -1;
    bool bPC = false;
    for (uint32 i=0; i<nLen; i++)
    {
      uint32 n = nLen-i-1;
      char c = s[n];
      if (c == '.')
        nEnd = n;
      else
      if (!bPC)
      {
        if (c == '@' || c == '/')
          bPC = true;
      }
      else
      if (c == '/')
      {
        nStart = n+1;
        break;
      }
    }
    if (nStart < 0 || nEnd < 0)
    {
      SAFE_DELETE(pRes);
      continue;
    }
    char str[128];
    memcpy(str, &s[nStart], nEnd-nStart);
    str[nEnd-nStart] = 0;
    if (bCheckSharedCache && !strnicmp(str, "_shared", 7))
    {
      if (sIsSharedLevelCacheValid(pLookupLevel, pRes))
      {
        SAFE_DELETE(pRes);
        continue;
      }
    }
    CCryNameTSCRC Name = str;
    FXCompressedShadersItor it = CHWShader::m_CompressedShaders.find(Name);
    SHWActivatedShader *pAS = NULL;
    if (it == CHWShader::m_CompressedShaders.end())
    {
      pAS = new SHWActivatedShader;
      pAS->m_bPersistent = bPersistent;
      CHWShader::m_CompressedShaders.insert(FXCompressedShadersItor::value_type(Name, pAS));
    }
    else
      pAS = it->second;
    ResDir *pDir = pRes->mfGetDirectory();
    for (uint32 i=0; i<pDir->size(); i++)
    {
      SDirEntry &DE = (*pDir)[i];
      if (CRenderer::CV_r_shadersdebug==3)
        iLog->Log("---Cache: PreactivateForLevel %s': 0x%x", pRes->mfGetFileName(), DE.Name.get());

			FXCompressedShaderRemapItor itR = pAS->m_Remap.find(DE.Name);
			uint32 nIDDev = DE.offset;
      assert (nIDDev > 0);
      if (itR == pAS->m_Remap.end())
			{
        pAS->m_Remap.insert(FXCompressedShaderRemapItor::value_type(DE.Name, DE.offset));
				itR = pAS->m_Remap.find(DE.Name);
			}
      FXCompressedShaderItor itS = pAS->m_CompressedShaders.find(itR->second);
      if (itS == pAS->m_CompressedShaders.end())
      {
				uint32 nSizeCompressed;
				uint32 nSizeDecompressed;
        byte *pDataCompressed = pRes->mfFileReadCompressed(&DE, nSizeDecompressed, nSizeCompressed);
				if (!pDataCompressed)
				{
					SAFE_DELETE_ARRAY(pDataCompressed);
					bRes = false;
					continue;
				}

				// only store compressed data - don't store token data for example because this is not compressed
				if (nSizeCompressed == nSizeDecompressed)
				{
					SAFE_DELETE_ARRAY(pDataCompressed);
					continue;
				}

				assert(nSizeCompressed < 65536 && nSizeDecompressed < 65536);
				if (nSizeCompressed > 65536 || nSizeDecompressed > 65536)
        {
					CryFatalError("size of shader to big for int 16");
          SAFE_DELETE_ARRAY(pDataCompressed);
          bRes = false;
          continue;
        }

				SCompressedData CD;
				CD.m_nSizeCompressedShader = nSizeCompressed;
				CD.m_nSizeDecompressedShader = nSizeDecompressed;        
        CD.m_pCompressedShader = pDataCompressed;
        assert (CD.m_nSizeCompressedShader != CD.m_nSizeDecompressedShader);

        /*byte *pData = new byte[CD.m_nSizeDecompressedShader+1];
        pData[CD.m_nSizeDecompressedShader] = 0xaa;
        Decodem(CD.m_pCompressedShader, pData, CD.m_nSizeCompressedShader);
        assert(pData[CD.m_nSizeDecompressedShader] == 0xaa);
        SShaderCacheHeaderItem *pIt = (SShaderCacheHeaderItem *)pData;
        if (CParserBin::m_bEndians)
          SwapEndian(*pIt, eBigEndian);
        SAFE_DELETE_ARRAY(pData);*/

        pAS->m_CompressedShaders.insert(FXCompressedShaderItor::value_type(nIDDev, CD));
      }
      else
      {
#ifdef _DEBUG
				uint32 nSizeCompressed;
				uint32 nSizeDecompressed;
				byte *pDataCompressed = pRes->mfFileReadCompressed(&DE, nSizeDecompressed, nSizeCompressed);
				assert(nSizeCompressed < 65536 && nSizeDecompressed < 65536);
        assert(pDataCompressed);
        if (pDataCompressed)
        {
          SCompressedData &CD1 = itS->second;
          assert(CD1.m_nSizeCompressedShader == nSizeCompressed);
          SAFE_DELETE_ARRAY(pDataCompressed);
        }
#endif
      }
    }
    SAFE_DELETE(pRes);
  } while (gEnv->pCryPak->FindNext(handle, &fileinfo) != -1);

  gEnv->pCryPak->FindClose (handle);

  return bRes;
}

int SHWActivatedShader::Size()
{
  int nSize = sizeof(SHWActivatedShader);
  nSize += sizeOfMap(m_CompressedShaders);
  nSize += sizeOfMapS(m_Remap);

  return nSize;
}

void SHWActivatedShader::GetMemoryUsage(ICrySizer* pSizer) const
{
	pSizer->AddObject(this, sizeof(SHWActivatedShader));
	pSizer->AddObject(m_CompressedShaders);
	pSizer->AddObject(m_Remap);
}

SHWActivatedShader::~SHWActivatedShader()
{
  FXCompressedShaderItor it;
  for (it=m_CompressedShaders.begin(); it!=m_CompressedShaders.end(); ++it)
  {
    SCompressedData& Data = it->second;
    SAFE_DELETE_ARRAY(Data.m_pCompressedShader);
  }
  m_CompressedShaders.clear();
  m_Remap.clear();
}
bool CShaderMan::mfReleasePreactivatedShaderData()
{
  bool bRes = true;
  FXCompressedShadersItor it;
  std::vector<CCryNameTSCRC> DelStuff;
  for (it=CHWShader::m_CompressedShaders.begin(); it!=CHWShader::m_CompressedShaders.end(); ++it)
  {
    SHWActivatedShader *pAS = it->second;
    if (!pAS->m_bPersistent)
    {
      SAFE_DELETE(pAS);
      DelStuff.push_back(it->first);
    }
  }
  uint32 i;
  for (i=0; i<DelStuff.size(); i++)
  {
    CHWShader::m_CompressedShaders.erase(DelStuff[i]);
  }
  return true;
}

bool CShaderMan::mfPreactivateShaders2(
	const char *szPak, const char *szPath, bool bPersistent, const char* szBindRoot)
{
  //mfReleasePreactivatedShaderData();

  bool bRes = true;

	// register pak
	if (szPak && strlen(szPak) > 0)
	{
		if (!gEnv->pCryPak->OpenPack(szBindRoot, szPak,  ICryPak::FLAGS_PAK_IN_MEMORY | ICryPak::FLAGS_PATH_REAL))
			return false;

		// Load pak to memory.
		gEnv->pCryPak->LoadPakToMemory( szPak, true );
	}

	string szPathPerLevel = szPath;
  if (CParserBin::m_nPlatform == SF_D3D10)
    szPathPerLevel += "d3d10/";
  else
  if (CParserBin::m_nPlatform == SF_D3D11)
    szPathPerLevel += "d3d11/";
  else
  if (CParserBin::m_nPlatform == SF_PS3)
    szPathPerLevel += "ps3/";
  else
  if (CParserBin::m_nPlatform == SF_XENON)
    szPathPerLevel += "x360/";
  else
	if (CParserBin::m_nPlatform == SF_CAFE)
		szPathPerLevel += "cafe/";
	else
    szPathPerLevel += "d3d9/";

	string szPathGlobal = gRenDev->m_cEF.m_ShadersCache;

  CResFileLookupDataMan LevelLookup;
  bool bLoaded = LevelLookup.LoadData(szPathPerLevel + "lookupdata.bin", CParserBin::m_bEndians);
  if (bLoaded)
  {
		bRes &= mfPreactivate2(LevelLookup, szPathPerLevel + "cgcshaders", 
			szPathGlobal + "cgcshaders", false, bPersistent);
		bRes &= mfPreactivate2(LevelLookup, szPathPerLevel + "cgdshaders", 
			szPathGlobal + "cgdshaders", false, bPersistent);
		bRes &= mfPreactivate2(LevelLookup, szPathPerLevel + "cggshaders", 
			szPathGlobal + "cggshaders", false, bPersistent);
		bRes &= mfPreactivate2(LevelLookup, szPathPerLevel + "cghshaders", 
			szPathGlobal + "cghshaders", false, bPersistent);
    bRes &= mfPreactivate2(LevelLookup, szPathPerLevel + "cgpshaders", 
			szPathGlobal + "cgpshaders", false, bPersistent);
    bRes &= mfPreactivate2(LevelLookup, szPathPerLevel + "cgvshaders", 
			szPathGlobal + "cgvshaders", true, bPersistent);
  }

	/*
	int n = 0;
	int nSize = 0;
	int nSizeD = 0;
	int nSizeAll = 0;
	for (FXCompressedShadersItor it=CHWShader::m_CompressedShaders.begin(); it!=CHWShader::m_CompressedShaders.end(); ++it)
	{
		SHWActivatedShader *pAS = it->second;
		for (FXCompressedShaderItor itor=pAS->m_CompressedShaders.begin(); itor!=pAS->m_CompressedShaders.end(); ++itor)
		{
			n++;
			SCompressedData& Data = itor->second;
			nSize += Data.m_nSizeCompressedShader;
			nSizeD += Data.m_nSizeDecompressedShader;
		}
	}
	nSizeAll = sizeOfMapP(CHWShader::m_CompressedShaders);
	*/

	if (szPak && strlen(szPak) > 0)
	{
		// Unload pak from memory.
		gEnv->pCryPak->LoadPakToMemory( szPak, false );

		// release pak from list
		gEnv->pCryPak->ClosePack(szPak, ICryPak::FLAGS_PATH_REAL);
	}

  return bRes;
}


void CHWShader_D3D::mfLogShaderCacheMiss(bool bGlobal, SHWSInstance *pInst)
{
	CShaderMan &Man = gRenDev->m_cEF;

	// update the stats
	if (bGlobal)
		Man.m_ShaderCacheStats.m_nGlobalShaderCacheMisses++;
	else
		Man.m_ShaderCacheStats.m_nPerLevelShaderCacheMisses++;

	// don't do anything else if CVar is disabled and no callback is registered
	if (CRenderer::CV_r_shaderslogcachemisses == 0 && Man.m_ShaderCacheMissCallback == 0)
		return;





	char nameCache[256];
	strcpy(nameCache, GetName());
	char *s = strchr(nameCache, '(');
	if (s)
		s[0] = 0;
	string sNew;
	SShaderCombIdent Ident = pInst->m_Ident;
	Ident.m_GLMask = m_nMaskGenFX;
	gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, nameCache, 0, &sNew, 0);
	SCacheCombination cmb;
	cmb.Name = gRenDev->m_cEF.m_ShadersLevelName;
	cmb.nCount = pInst->m_nUsed;
	cmb.CacheName = sNew;

	string sEntry;

#ifndef CAFE
	sEntry = "[";
	if (bGlobal)
	{





		sEntry += "ShaderList_PC.txt";

	} else {

		// don't log if we don't have a valid level
		if (gRenDev->m_cEF.m_ShadersLevelName.length() == 0)
			return;

		sEntry = "[";
		sEntry += gRenDev->m_cEF.m_ShadersFilter;
		sEntry += "/";
		sEntry += gRenDev->m_cEF.m_ShadersLevelName;
		sEntry += "ShaderList.txt";
	}
	sEntry += "]";
#endif
	sEntry += sNew;

	CCryNameTSCRC cryName(sEntry);

	// do we already contain this entry (vec is sorted so lower bound gives us already the good position to insert)
	CShaderMan::ShaderCacheMissesVec::iterator it = std::lower_bound(Man.m_ShaderCacheMisses.begin(), Man.m_ShaderCacheMisses.end(), cryName);
	if (it == Man.m_ShaderCacheMisses.end() || cryName != (*it))
	{
 		Man.m_ShaderCacheMisses.insert(it, cryName);

		if (CRenderer::CV_r_shaderslogcachemisses)
		{
			FILE* pFile = fopen(Man.m_ShaderCacheMissPath.c_str() ,"a+" );
			if (pFile)
			{
				fprintf(pFile, "%s\n", sEntry.c_str());
				fclose(pFile);
			}
		}

		// call callback if provided to inform client about misses
		if (Man.m_ShaderCacheMissCallback)
		{
			(*Man.m_ShaderCacheMissCallback)(sEntry.c_str());
		}
	}
}

#ifndef _RELEASE

void CHWShader_D3D::mfCommitCombination(SHWSInstance *pInst, int nFrame, int nFrameDiff)
{
  if (pInst->m_nFrameSubmit==gRenDev->m_cEF.m_nFrameSubmit && pInst->m_nUsedFrame < nFrame-nFrameDiff)
    return;
  pInst->m_nFrameSubmit = gRenDev->m_cEF.m_nFrameSubmit;

  char nameCache[256];
  strcpy(nameCache, GetName());
  char *s = strchr(nameCache, '(');
  if (s)
    s[0] = 0;
  string sNew;
  SShaderCombIdent Ident = pInst->m_Ident;
  Ident.m_GLMask = m_nMaskGenFX;
  gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, nameCache, 0, &sNew, 0);
  SCacheCombination cmb;
  cmb.Name = gRenDev->m_cEF.m_ShadersLevelName;
  cmb.nCount = pInst->m_nUsed;
  cmb.CacheName = sNew;
  CShaderMan &Man = gRenDev->m_cEF;
  FXShaderCacheCombinationsItor pCheck = Man.m_ShaderCacheCombinationsLevelsFull.find(cmb.CacheName);
  if (pCheck == Man.m_ShaderCacheCombinationsLevelsFull.end())
  {
    Man.m_ShaderCacheCombinationsLevelsFull.insert(FXShaderCacheCombinationsItor::value_type(cmb.CacheName, cmb));
    if (Man.m_FPCacheCombinationsLevels)
      gEnv->pCryPak->FPrintf(Man.m_FPCacheCombinationsLevels, "[%s]<%d>%s\n", cmb.Name.c_str(), cmb.nCount, sNew.c_str());
  }
  else
  {
    SCacheCombination &c = pCheck->second;
    c.nCount = cmb.nCount;
  }
}

void CHWShader_D3D::mfCommitCombinations(int nFrame, int nFrameDiff)
{
  uint32 i;
  for (i=0; i<m_Insts.size(); i++)
  {
    SHWSInstance *pShInst = &m_Insts[i];
    mfCommitCombination(pShInst, nFrame, nFrameDiff);
  }
}

void CShaderMan::mfFlushCurPLCombinations(bool bAll)
{ 
	FUNCTION_PROFILER_RENDERER;

  if (m_ShadersLevelName.empty()) // || true)
    return;

	ScopedSwitchToGlobalHeap useGlobalHeap;

	/*
	// also collect the stats even when the remote compiler is disabled
	if (!CRenderer::CV_r_shadersremotecompiler)
		return;
	*/

  static int nStep = 0;
  int nDiff = bAll ? 0 : 60;
  uint32 nFrame = gRenDev->m_nFrameSwapID;
  if (m_nFrameLastSubmitted+nDiff>nFrame)
    return;
  nDiff *= 3;

  CCryNameTSCRC Name;
  SResourceContainer *pRL;
  if (nStep == 0) // Vertex
  {
    Name = CHWShader::mfGetClassName(eHWSC_Vertex);
    pRL = CBaseResource::GetResourcesForClass(Name);
    if (pRL)
    {
      ResourcesMapItor itor;
      for (itor=pRL->m_RMap.begin(); itor!=pRL->m_RMap.end(); itor++)
      {
        CHWShader_D3D *vsh = (CHWShader_D3D *)itor->second;
        vsh->mfCommitCombinations(nFrame, nDiff);
      }
    }
  }
  else
  if (nStep == 1) // Pixel
  {
    Name = CHWShader::mfGetClassName(eHWSC_Pixel);
    pRL = CBaseResource::GetResourcesForClass(Name);
    if (pRL)
    {
      ResourcesMapItor itor;
      for (itor=pRL->m_RMap.begin(); itor!=pRL->m_RMap.end(); itor++)
      {
        CHWShader_D3D *vsh = (CHWShader_D3D *)itor->second;
        vsh->mfCommitCombinations(nFrame, nDiff);
      }
    }
  }
  else
  if (nStep == 2) // Shared
  {
    uint32 i, j, n;
    CHWShader_D3D::InstanceMapItor it;
    for (it=CHWShader_D3D::m_SharedInsts.begin(); it!=CHWShader_D3D::m_SharedInsts.end(); it++)
    {
      CHWShader_D3D::SHWSSharedList *pList = it->second;
      if (!pList)
        continue;
      const string& Nm = it->first;
      if (pList->m_SharedNames.size())
      {
        for (i=0; i<pList->m_SharedInsts.size(); i++)
        {
          CHWShader_D3D::SHWSSharedInstance *pSInst = &pList->m_SharedInsts[i];
          for (j=0; j<pSInst->m_Insts.size(); j++)
          {
            CHWShader_D3D::SHWSInstance *pInst = &pSInst->m_Insts[j];
						if (pInst->m_nFrameSubmit==gRenDev->m_cEF.m_nFrameSubmit && pInst->m_nUsedFrame < (int)(nFrame-nDiff))
							continue;
						pInst->m_nFrameSubmit = gRenDev->m_cEF.m_nFrameSubmit;

            char name[256];
            for (n=0; n<pList->m_SharedNames.size(); n++)
            {
              sprintf(name, "%s@%s", pList->m_SharedNames[n].m_Name.c_str(), Nm.c_str());
              string sNew;
              SShaderCombIdent Ident = pInst->m_Ident;
              Ident.m_GLMask = pSInst->m_GLMask;
              mfInsertNewCombination(Ident, pInst->m_eClass, name, 0, &sNew, 0);
              SCacheCombination cmb;
              cmb.Name = m_ShadersLevelName;
              cmb.nCount = pInst->m_nUsed;
              cmb.CacheName = sNew;
              FXShaderCacheCombinationsItor pCheck = m_ShaderCacheCombinationsLevelsFull.find(cmb.CacheName);
              if (pCheck == m_ShaderCacheCombinationsLevelsFull.end())
              {
                m_ShaderCacheCombinationsLevelsFull.insert(FXShaderCacheCombinationsItor::value_type(cmb.CacheName, cmb));
                if (m_FPCacheCombinationsLevels)
                  gEnv->pCryPak->FPrintf(m_FPCacheCombinationsLevels, "[%s]<%d>%s\n", cmb.Name.c_str(), cmb.nCount, sNew.c_str());
              }
              else
              {
                SCacheCombination &c = pCheck->second;
                c.nCount = cmb.nCount;
              }
            }
          }
        }
      }
    }
  }
  nStep++;
  if (nStep >= 3)
    nStep = 0;

  if (m_FPCacheCombinationsLevels)
    gEnv->pCryPak->FFlush(m_FPCacheCombinationsLevels);

  m_nFrameLastSubmitted = nFrame;
}
#endif

static char *sSetParameterExp(char *szExpr, Vec4& vVal, DynArray<SShaderParam>& Params, bool& bResult);

static char *sSetOperand(char *szExpr, Vec4& vVal, DynArray<SShaderParam>& Params, bool& bResult)
{
  char temp[256];
  SkipCharacters(&szExpr, kWhiteSpace);
  if (*szExpr == '(')
  {
    szExpr = sSetParameterExp(szExpr, vVal, Params, bResult);
  }
  else
  {
    fxFillNumber(&szExpr, temp);
    if (temp[0] != '.' && (temp[0]<'0' || temp[0]>'9'))
    {
      bResult &= SShaderParam::GetValue(temp, &Params, &vVal[0], 0);
      //assert(bF);
    }
    else
      vVal[0] = shGetFloat(temp);
  }
  return szExpr;
}

static char *sSetParameterExp(char *szExpr, Vec4& vVal, DynArray<SShaderParam>& Params, bool& bResult)
{
  if (szExpr[0] != '(')
    return NULL;
  char expr[1024];
  int n = 0;
  int nc = 0;
  char theChar;
  while (theChar = *szExpr)
  {
    if (theChar == '(')
    {
      n++;
      if (n == 1)
      {
        szExpr++;
        continue;
      }
    }
    else
    if (theChar == ')')
    {
      n--;
      if (!n)
      {
        szExpr++;
        break;
      }
    }
    expr[nc++] = theChar;
    szExpr++;
  }
  expr[nc++] = 0;
  assert(!n);
  if (n)
    return NULL;

  char *szE = expr;
  Vec4 vVals[2];
  vVals[0] = Vec4(0,0,0,0);
  szE = sSetOperand(szE, vVals[0], Params, bResult);
  SkipCharacters(&szE, kWhiteSpace);
  char szOp = *szE++;
  vVals[1] = Vec4(0,0,0,0);
  SkipCharacters(&szE, kWhiteSpace);
  szE = sSetOperand(szE, vVals[1], Params, bResult);

  switch (szOp)
  {
    case '+':
      vVal[0] = vVals[0][0] + vVals[1][0];
      break;
    case '-':
      vVal[0] = vVals[0][0] - vVals[1][0];
      break;
    case '*':
      vVal[0] = vVals[0][0] * vVals[1][0];
      break;
    case '/':
      vVal[0] = vVals[0][0]; 
      if( vVals[1][0] )
        vVal[0] /= vVals[1][0];
      break;
  }

  return (char *)szExpr;
}

static bool sSetParameter(SFXParam *pPR, Vec4 *Constants, DynArray<SShaderParam>& Params, int nOffs, EHWShaderClass eSHClass)
{
  uint32 nFlags = pPR->GetParamFlags();
  bool bFound = false;
  for (int i=0; i<4; i++)
  {
    if (nFlags & PF_AUTOMERGED)
    {
      string n = pPR->GetCompName(i);
      bool bF = SShaderParam::GetValue(n.c_str(), &Params, &Constants[pPR->m_nRegister[eSHClass]-nOffs][0], i);
      if (!bF)
      {
        string v = pPR->GetParamComp(i);
        if (v[0] == '(')
        {
          Vec4 vVal = Vec4(-10000, -10000, -10000, -10000);
          bool bResult = true;
          sSetParameterExp((char *)v.c_str(), vVal, Params, bResult);
          if (bResult)
          {
            Constants[pPR->m_nRegister[eSHClass]-nOffs][i] = vVal[0];
            if (vVal[0] != -10000)
              bF = true;
          }
        }
      }
      bFound |= bF;
    }
    else
      bFound |= SShaderParam::GetValue(pPR->m_Name.c_str(), &Params, &Constants[pPR->m_nRegister[eSHClass]-nOffs][0], i);
  }
  return bFound;
}


static int s_nClass;
struct CompareItem
{
	bool operator()(const SFXParam *a, const SFXParam *b)
	{
		return (a->m_nRegister[s_nClass] < b->m_nRegister[s_nClass]);
	}
};

void SRenderShaderResources::RT_UpdateConstants(IShader *pISH)
{
  int32 i, j, m;
	int n;

  //assert(gRenDev->m_pRT->IsRenderThread());

  CShader *pSH = (CShader *)pISH;
  assert(pSH->m_Flags & EF_LOADED); // Make sure shader is parsed

  /*if (m_szMaterialName && (!strcmp(m_szMaterialName, "wall_base") || !strcmp(m_szMaterialName, "street")))
  {
    int nnn = 0;
  }
  if (m_Textures[0] && strstr(m_Textures[0]->m_Name.c_str(), "overpass_road"))
  {
    int nnn = 0;
  }
  if (m_Id == 0x127)
  {
    int nnn = 0;
  }*/

  SShaderFXParams& FXParams = gRenDev->m_cEF.m_Bin.mfGetFXParams(pSH);

  DynArray<SShaderParam> PublicParams = pSH->GetPublicParams();
  // Copy material tweakables to shader public params
  for (i=0; i<m_ShaderParams.size(); i++)
  {
    SShaderParam& TW = m_ShaderParams[i];
    for (j=0; j<PublicParams.size(); j++)
    {
      SShaderParam& PB = PublicParams[j];
      if (!strcmp(PB.m_Name, TW.m_Name))
      {
        bool bSkip = false;
        switch (PB.m_Type)
        {
          case eType_FLOAT:
          case eType_HALF:
            PB.m_Value.m_Float = TW.m_Value.m_Color[0];
            PB.m_Value.m_Color[1] = TW.m_Value.m_Color[1];
            PB.m_Value.m_Color[2] = TW.m_Value.m_Color[2];
            PB.m_Value.m_Color[3] = TW.m_Value.m_Color[3];
            break;
          case eType_INT:
            PB.m_Value.m_Int = (int)TW.m_Value.m_Color[0];
            break;
          case eType_VECTOR:
            PB.m_Value.m_Color[0] = TW.m_Value.m_Color[0];
            PB.m_Value.m_Color[1] = TW.m_Value.m_Color[1];
            PB.m_Value.m_Color[2] = TW.m_Value.m_Color[2];
            PB.m_Value.m_Color[3] = TW.m_Value.m_Color[3];
            break;
          case eType_FCOLOR:
            PB.m_Value.m_Color[0] = TW.m_Value.m_Color[0];
            PB.m_Value.m_Color[1] = TW.m_Value.m_Color[1];
            PB.m_Value.m_Color[2] = TW.m_Value.m_Color[2];
            PB.m_Value.m_Color[3] = TW.m_Value.m_Color[3];
            break;
          default:
            bSkip = true;
            break;
            // skip
        }
        TW = PB;
        break;
      }
    }
    if (j==PublicParams.size())
    {
      int nnn = 0; // Public parameter with this name doesn't exist
    }
  }

  std::vector<SFXParam *> VSParams;
  std::vector<SFXParam *> PSParams;
  std::vector<SFXParam *> GSParams;

  uint32 nMergeMaskPS = 1;
  uint32 nMergeMaskVS = 2;
  uint32 nMergeMaskGS = 4;

  bool bHasGS = false;
  for (i=0; i<(int)pSH->m_HWTechniques.Num(); i++)
  {
    SShaderTechnique *pTech = pSH->m_HWTechniques[i];
    for (j=0; j<(int)pTech->m_Passes.Num(); j++)
    {
      SShaderPass *pPass = &pTech->m_Passes[j];
      CHWShader_D3D *pVS = (CHWShader_D3D *)pPass->m_VShader;
      CHWShader_D3D *pPS = (CHWShader_D3D *)pPass->m_PShader;
#if !defined (PS3) && !defined (XENON) && !defined(CAFE)
      CHWShader_D3D *pGS = (CHWShader_D3D *)pPass->m_GShader;
      CHWShader_D3D *pHS = (CHWShader_D3D *)pPass->m_HShader;
      CHWShader_D3D *pDS = (CHWShader_D3D *)pPass->m_DShader;
      CHWShader_D3D *pCS = (CHWShader_D3D *)pPass->m_CShader;
#endif
      assert(pVS && pPS);
      if (pVS)
      {
        for (n=0; n<(int)FXParams.m_FXParams.size(); n++)
        {
          SFXParam *pPR = &FXParams.m_FXParams[n];
          if (pPR->m_nFlags & (nMergeMaskVS << PF_MERGE_SHIFT))
            continue;
          if (pPR->m_nCB == CB_PER_MATERIAL)
          {
            if(pPR->m_nRegister[eHWSC_Vertex]<FIRST_REG_PM[eHWSC_Vertex] || pPR->m_nRegister[eHWSC_Vertex]>=10000)
              continue;
            for (m=0; m<(int)VSParams.size(); m++)
            {
              if (VSParams[m]->m_Name == pPR->m_Name)
                break;
            }
            if (m == VSParams.size())
              VSParams.push_back(pPR);
          }
        }
      }

      if (pPS)
      {
        for (n=0; n<(int)FXParams.m_FXParams.size(); n++)
        {
          SFXParam *pPR = &FXParams.m_FXParams[n];
          if (pPR->m_nFlags & (nMergeMaskPS << PF_MERGE_SHIFT))
            continue;
          if (pPR->m_nCB == CB_PER_MATERIAL)
          {
            if(pPR->m_nRegister[eHWSC_Pixel]<FIRST_REG_PM[eHWSC_Pixel] || pPR->m_nRegister[eHWSC_Pixel]>=10000)
              continue;
            for (m=0; m<(int)PSParams.size(); m++)
            {
              if (PSParams[m]->m_Name == pPR->m_Name)
                break;
            }
            if (m == PSParams.size())
              PSParams.push_back(pPR);
          }
        }
      }
#if !defined(PS3) && !defined(XENON) && !defined(CAFE)
      if (pGS)
      {
        for (n=0; n<(int)FXParams.m_FXParams.size(); n++)
        {
          SFXParam *pPR = &FXParams.m_FXParams[n];
          if (pPR->m_nFlags & (nMergeMaskVS << PF_MERGE_SHIFT))
            continue;
          if (pPR->m_nCB == CB_PER_MATERIAL)
          {
            if(pPR->m_nRegister[eHWSC_Geometry]<FIRST_REG_PM[eHWSC_Vertex] || pPR->m_nRegister[eHWSC_Geometry]>=10000)
              continue;
            for (m=0; m<(int)VSParams.size(); m++)
            {
              if (VSParams[m]->m_Name == pPR->m_Name)
                break;
            }
            if (m == VSParams.size())
              VSParams.push_back(pPR);
          }
        }
      }
      if (pHS)
      {
        for (n=0; n<(int)FXParams.m_FXParams.size(); n++)
        {
          SFXParam *pPR = &FXParams.m_FXParams[n];
          if (pPR->m_nFlags & (nMergeMaskVS << PF_MERGE_SHIFT))
            continue;
          if (pPR->m_nCB == CB_PER_MATERIAL)
          {
            if(pPR->m_nRegister[eHWSC_Hull]<FIRST_REG_PM[eHWSC_Vertex] || pPR->m_nRegister[eHWSC_Hull]>=10000)
              continue;
            for (m=0; m<(int)VSParams.size(); m++)
            {
              if (VSParams[m]->m_Name == pPR->m_Name)
                break;
            }
            if (m == VSParams.size())
              VSParams.push_back(pPR);
          }
        }
      }
      if (pDS)
      {
        for (n=0; n<(int)FXParams.m_FXParams.size(); n++)
        {
          SFXParam *pPR = &FXParams.m_FXParams[n];
          if (pPR->m_nFlags & (nMergeMaskVS << PF_MERGE_SHIFT))
            continue;
          if (pPR->m_nCB == CB_PER_MATERIAL)
          {
            if(pPR->m_nRegister[eHWSC_Domain]<FIRST_REG_PM[eHWSC_Vertex] || pPR->m_nRegister[eHWSC_Domain]>=10000)
              continue;
            for (m=0; m<(int)VSParams.size(); m++)
            {
              if (VSParams[m]->m_Name == pPR->m_Name)
                break;
            }
            if (m == VSParams.size())
              VSParams.push_back(pPR);
          }
        }
      }
      if (pCS)
      {
        for (n=0; n<(int)FXParams.m_FXParams.size(); n++)
        {
          SFXParam *pPR = &FXParams.m_FXParams[n];
          if (pPR->m_nFlags & (nMergeMaskVS << PF_MERGE_SHIFT))
            continue;
          if (pPR->m_nCB == CB_PER_MATERIAL)
          {
            if(pPR->m_nRegister[eHWSC_Compute]<FIRST_REG_PM[eHWSC_Vertex] || pPR->m_nRegister[eHWSC_Compute]>=10000)
              continue;
            for (m=0; m<(int)VSParams.size(); m++)
            {
              if (VSParams[m]->m_Name == pPR->m_Name)
                break;
            }
            if (m == VSParams.size())
              VSParams.push_back(pPR);
          }
        }
      }
#endif
    }
  }
  s_nClass = eHWSC_Vertex;
  if (VSParams.size() > 1)
  {
    std::sort(VSParams.begin(), VSParams.end(), CompareItem());
  }
  s_nClass = eHWSC_Pixel;
  if (PSParams.size() > 1)
  {
    std::sort(PSParams.begin(), PSParams.end(), CompareItem());
  }













































  std::vector<Vec4> *pCBVS = &m_Constants[eHWSC_Vertex];
  std::vector<Vec4> *pCBPS = &m_Constants[eHWSC_Pixel];
  SFXParam *pPR;
  int nFirstVS = FIRST_REG_PM[eHWSC_Vertex];
  int nLastVS = -1;
  int nFirstPS = FIRST_REG_PM[eHWSC_Pixel];
  int nLastPS = -1;
  if (m_szMaterialName && strstr(m_szMaterialName, "bigPlane"))
  {
    int nnn = 0;
  }

  if (VSParams.size())
  {
    nLastVS = VSParams[VSParams.size()-1]->m_nRegister[eHWSC_Vertex];
    assert(nLastVS>=FIRST_REG_PM[eHWSC_Vertex] && VSParams[0]->m_nRegister[eHWSC_Vertex]>=FIRST_REG_PM[eHWSC_Vertex]);
  }



  nLastVS = max(nFirstVS+NUM_VS_PM-1, nLastVS);
  int nCur = pCBVS->size();
  if (nCur < nLastVS+1-nFirstVS)
    pCBVS->resize(nLastVS+1-nFirstVS);
  for (int ii=nCur; ii<=nLastVS-nFirstVS; ii++)
  {
    (*pCBVS)[ii] = Vec4(-100000,-200000,-300000,-400000);
  }

  if (PSParams.size())
  {
    nLastPS = PSParams[PSParams.size()-1]->m_nRegister[eHWSC_Pixel];
    assert(nLastPS>=nFirstPS && PSParams[0]->m_nRegister[eHWSC_Pixel]>=nFirstPS);
  }



  nLastPS = max(nFirstPS+NUM_PS_PM-1, nLastPS);
  nCur = pCBPS->size();
  if (nCur < nLastPS+1-nFirstPS)
    pCBPS->resize(nLastPS+1-nFirstPS);
  for (int ii=nCur; ii<=nLastPS-nFirstPS; ii++)
  {
    (*pCBPS)[ii] = Vec4(-100000,-200000,-300000,-400000);
  }

  if (PublicParams.size())
  {
    for (i=0; i<(int)VSParams.size(); i++)
    {
      pPR = VSParams[i];
      sSetParameter(pPR, &(*pCBVS)[0], PublicParams, nFirstVS, eHWSC_Vertex);
    }
    for (i=0; i<(int)PSParams.size(); i++)
    {
      pPR = PSParams[i];
      sSetParameter(pPR, &(*pCBPS)[0], PublicParams, nFirstPS, eHWSC_Pixel);
    }
    }









#ifdef DIRECT3D10
  D3D11_BUFFER_DESC bd;
  ZeroStruct(bd);
  HRESULT hr;

  bd.Usage = D3D11_USAGE_DEFAULT;
  bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
  bd.CPUAccessFlags = 0;
  bd.MiscFlags = 0;

  //bd.Usage = D3D11_USAGE_DYNAMIC;
  //bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;	
  ID3D11Buffer **ppBuf = alias_cast<ID3D11Buffer**>(&m_pCB[eHWSC_Vertex]);
  CHWShader_D3D::mfUnbindCB(*ppBuf);
  SAFE_RELEASE(*ppBuf);
  if (m_Constants[eHWSC_Vertex].size())
  {






    bd.ByteWidth = m_Constants[eHWSC_Vertex].size() * sizeof(Vec4);
    hr = gcpRendD3D->m_pd3dDevice->CreateBuffer(&bd, NULL, ppBuf);
    assert(SUCCEEDED(hr));
    gcpRendD3D->m_pd3dDeviceContext->UpdateSubresource(*ppBuf, 0, NULL, &m_Constants[eHWSC_Vertex][0], 0, 0);

    //void *pData;
    //(*ppBuf)->Map(D3D11_MAP_WRITE_DISCARD, NULL, (void **)&pData);
    //memcpy(pData, &m_Constants[eHWSC_Vertex][0], bd.ByteWidth);
    //(*ppBuf)->Unmap();
  }	
  ppBuf = alias_cast<ID3D11Buffer**>(&m_pCB[eHWSC_Pixel]);
  CHWShader_D3D::mfUnbindCB(*ppBuf); 
  SAFE_RELEASE(*ppBuf);
  if (m_Constants[eHWSC_Pixel].size())
  {



    bd.ByteWidth = m_Constants[eHWSC_Pixel].size() * sizeof(Vec4);

    hr = gcpRendD3D->m_pd3dDevice->CreateBuffer(&bd, NULL, ppBuf);
    assert(SUCCEEDED(hr));
    















		if((m_ResFlags & MTL_FLAG_ADDITIVE) && (m_Constants[eHWSC_Pixel].size() > PS_EMISSIVE_COL))
		{
			const uint32 numVecs = (PS_EMISSIVE_COL - PS_DIFFUSE_COL) + 1;
			const uint32 startVec = PS_DIFFUSE_COL;
			const float opacity = m_Constants[eHWSC_Pixel][startVec][3];
			Vec4 m_tmpDiffuse[numVecs];

			memcpy(&m_tmpDiffuse[0], &m_Constants[eHWSC_Pixel][startVec][0], sizeof(Vec4)*numVecs);

			for(uint32 i = startVec; i<(startVec + numVecs); i++)
			{
				m_Constants[eHWSC_Pixel][i][0] *= opacity;
				m_Constants[eHWSC_Pixel][i][1] *= opacity;
				m_Constants[eHWSC_Pixel][i][2] *= opacity;
			}
			gcpRendD3D->m_pd3dDeviceContext->UpdateSubresource(*ppBuf, 0, NULL, &m_Constants[eHWSC_Pixel][0], 0, 0);

			memcpy( &m_Constants[eHWSC_Pixel][startVec][0], &m_tmpDiffuse[0], sizeof(Vec4)*numVecs);
		}
		else
		{
			//char pszTest[256];
			//sprintf( pszTest, "%.3f %.3f %.3f\n", m_Constants[eHWSC_Pixel][0]);
			//OutputDebugString(pszTest);
			gcpRendD3D->m_pd3dDeviceContext->UpdateSubresource(*ppBuf, 0, NULL, &m_Constants[eHWSC_Pixel][0], 0, 0);
		}

    //void *pData;
    //(*ppBuf)->Map(D3D11_MAP_WRITE_DISCARD, NULL, (void **)&pData);
    //memcpy(pData, &m_Constants[eHWSC_Pixel][0], bd.ByteWidth);
    //(*ppBuf)->Unmap();
  }
#endif
}

void SRenderShaderResources::CloneConstants(const IRenderShaderResources* pISrc)
{
  //assert(gRenDev->m_pRT->IsRenderThread());

  SRenderShaderResources *pSrc = (SRenderShaderResources *)pISrc;

	if (!pSrc)
	{
		for (int i=0; i<2; i++)
			m_Constants[i].clear();
#if defined(DIRECT3D10)
		ID3D11Buffer*& pCB0 = *(alias_cast<ID3D11Buffer**>(&m_pCB[eHWSC_Vertex]));
    CHWShader_D3D::mfUnbindCB(pCB0);
		SAFE_RELEASE(pCB0);
		ID3D11Buffer*& pCB1 = *(alias_cast<ID3D11Buffer**>(&m_pCB[eHWSC_Pixel]));
    CHWShader_D3D::mfUnbindCB(pCB1);
		SAFE_RELEASE(pCB1);
#endif
		return;
	}
	else
	{
		for (int i=0; i<2; i++)
			m_Constants[i] = pSrc->m_Constants[i];
#if defined(DIRECT3D10)
		{			
			ID3D11Buffer*& pCB0Dst = *(alias_cast<ID3D11Buffer**>(&m_pCB[eHWSC_Vertex]));
			ID3D11Buffer*& pCB0Src = *(alias_cast<ID3D11Buffer**>(&pSrc->m_pCB[eHWSC_Vertex]));
			if (pCB0Src)
				pCB0Src->AddRef();
			if (pCB0Dst)
      {
        CHWShader_D3D::mfUnbindCB(pCB0Dst); 
				pCB0Dst->Release();
      }
			pCB0Dst = pCB0Src;
		}
		{
			ID3D11Buffer*& pCB1Dst = *(alias_cast<ID3D11Buffer**>(&m_pCB[eHWSC_Pixel]));		
			ID3D11Buffer*& pCB1Src = *(alias_cast<ID3D11Buffer**>(&pSrc->m_pCB[eHWSC_Pixel]));
			if (pCB1Src)
				pCB1Src->AddRef();
			if (pCB1Dst)
      {
        CHWShader_D3D::mfUnbindCB(pCB1Dst);
				pCB1Dst->Release();
      }
			pCB1Dst = pCB1Src;
		}
#endif
	}
}

void SRenderShaderResources::ReleaseConstants()
{
  m_Constants[0].clear();
  m_Constants[1].clear();

#if defined (DIRECT3D10)
  if (m_pCB[eHWSC_Vertex])
  {
    gRenDev->m_pRT->RC_ReleaseCB(m_pCB[eHWSC_Vertex]);
    m_pCB[eHWSC_Vertex] = NULL;
  }
  if (m_pCB[eHWSC_Pixel])
  {
    gRenDev->m_pRT->RC_ReleaseCB(m_pCB[eHWSC_Pixel]);
    m_pCB[eHWSC_Pixel] = NULL;
  }
#endif
}

static void sChangeAniso(SEfResTexture *pTex)
{
  int nTS = pTex->m_Sampler.m_nTexState;
  if (nTS < 0 || nTS >= (int) CTexture::s_TexStates.size())
    return;
  int8 nAniso = min(CRenderer::CV_r_texminanisotropy, CRenderer::CV_r_texmaxanisotropy);
	if (nAniso <= 1)
		return;
  STexState *pTS = &CTexture::s_TexStates[nTS];
  STexState ST = *pTS;
	if (ST.m_nAnisotropy >= nAniso)
		return;
#if defined(DIRECT3D10)
	ST.m_pDeviceState=NULL;	//otherwise state change is not applied
#endif

#if defined (DIRECT3D9)
	if (gcpRendD3D->m_pd3dCaps->TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC)
		ST.m_nMinFilter = D3DTEXF_ANISOTROPIC;
	else
		ST.m_nMinFilter = D3DTEXF_LINEAR;

	if (gcpRendD3D->m_pd3dCaps->TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC)
		ST.m_nMagFilter = D3DTEXF_ANISOTROPIC;
	else
		ST.m_nMagFilter = D3DTEXF_LINEAR;

	ST.m_nMipFilter = D3DTEXF_LINEAR;
#else // #if defined (DIRECT3D9)
	if(nAniso>=16)
		ST.m_nMipFilter =
		ST.m_nMinFilter =
		ST.m_nMagFilter = FILTER_ANISO16X;
	else if(nAniso>=8)
		ST.m_nMipFilter =
		ST.m_nMinFilter =
		ST.m_nMagFilter = FILTER_ANISO8X;
	else if(nAniso>=4)
		ST.m_nMipFilter =
		ST.m_nMinFilter =
		ST.m_nMagFilter = FILTER_ANISO4X;
	else
		ST.m_nMipFilter =
		ST.m_nMinFilter =
		ST.m_nMagFilter = FILTER_ANISO2X;
#endif

  ST.m_nAnisotropy = nAniso;
  pTex->m_Sampler.m_nTexState = CTexture::GetTexState(ST);
}

void SRenderShaderResources::AdjustForSpec()
{
#if !defined (PS3) && !defined(XENON)
  if (m_Textures[EFTT_DIFFUSE])
    sChangeAniso(m_Textures[EFTT_DIFFUSE]);
  if (m_Textures[EFTT_BUMP])
    sChangeAniso(m_Textures[EFTT_BUMP]);
	if (m_Textures[EFTT_GLOSS])
		sChangeAniso(m_Textures[EFTT_GLOSS]);
#endif
}

